package com.gitee.huanminabc.jcommon.encryption;

import java.security.GeneralSecurityException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;

/**
 *  这个算法主要是用来生成验证码的,和令牌的
 *  而这个令牌一旦生成,就只会在指定的时间内有效
 *  可以理解为一次性的密码,过期了就无法使用
 */
public class LinAuthentication {

    private long mStartTime = 0; //起始时间
    private  long mTimeStep = 30;//时间步长
    private  int mCodeDigits = 6;//验证码位数

    public LinAuthentication() {
    }

    public LinAuthentication(long mStartTime, long mTimeStep, int mCodeDigits) {
        this.mStartTime = mStartTime;
        this.mTimeStep = mTimeStep;
        this.mCodeDigits = mCodeDigits;
    }

    public LinAuthentication(long mTimeStep, int mCodeDigits) {
        this.mTimeStep = mTimeStep;
        this.mCodeDigits = mCodeDigits;
    }


    public String getCurrentCode(String secret) throws OtpSourceException {
        long otp_state = getValueAtTime(System.currentTimeMillis() / 1000);
        return computePin(secret, otp_state);
    }

    private String computePin(String secret, long otp_state)
            throws OtpSourceException {
        if (secret == null || secret.isEmpty()) {
            throw new OtpSourceException("Null or empty secret");
        }
        try {
            //获取签名
            PasscodeGenerator.Signer signer = getSigningOracle(secret);
            PasscodeGenerator pcg = new PasscodeGenerator(signer, mCodeDigits);
            return pcg.generateResponseCode(otp_state);

        } catch (GeneralSecurityException e) {
            throw new OtpSourceException("Crypto failure", e);
        }
    }


    private long getValueAtTime(long time) {
        long timeSinceStartTime = time - mStartTime;
        if (timeSinceStartTime >= 0) {
            return timeSinceStartTime / mTimeStep;
        } else {
            return (timeSinceStartTime - (mTimeStep - 1)) / mTimeStep;
        }
    }


    private PasscodeGenerator.Signer getSigningOracle(String secret) {
        try {
            byte[] keyBytes = Base32String.decode(secret);
            final Mac mac = Mac.getInstance("HMACSHA1");
            mac.init(new SecretKeySpec(keyBytes, ""));

            return new PasscodeGenerator.Signer() {
                @Override
                public byte[] sign(byte[] data) {
                    return mac.doFinal(data);
                }
            };
        } catch (Base32String.DecodingException | NoSuchAlgorithmException | InvalidKeyException error) {
            //Log.e(LOCAL_TAG, error.getMessage());
        }

        return null;
    }

    public static class OtpSourceException extends Exception {

        public OtpSourceException(String message) {
            super(message);
        }

        public OtpSourceException(String message, Throwable cause) {
            super(message, cause);
        }
    }


}
